(function (b) {
    var a = {};
    a.config = {
        editable: true, lineHeight: 15, basePath: "",
        rect: {
            attr: { x: 10, y: 10, width: 100, height: 50, r: 5, fill: "90-#fff-#C0C0C0", stroke: "#000", "stroke-width": 1 },
            showType: "image&text", type: "state", name: { text: "state", "font-style": "italic" }, text: { text: '状态', "font-size": 13 },
            margin: 5, props: [], img: {}
        }, showPropsExtend:function(e, m, c){
            // add by zhanglongfei
        }, path: {
            attr: {
                path: { path: "M10 10L100 100", stroke: "#808080", fill: "none", "stroke-width": 4 },
                arrow: { path: "M10 10L10 10", stroke: "#808080", fill: "#808080", "stroke-width": 4, radius: 6 },
                fromDot: { width: 5, height: 5, stroke: "#fff", fill: "#000", cursor: "move", "stroke-width": 2 },
                toDot: { width: 5, height: 5, stroke: "#fff", fill: "#000", cursor: "move", "stroke-width": 2 },
                bigDot: { width: 5, height: 5, stroke: "#fff", fill: "#000", cursor: "move", "stroke-width": 2 },
                smallDot: { width: 5, height: 5, stroke: "#fff", fill: "#000", cursor: "move", "stroke-width": 3 }
            }, text: { text: "TO {to}", cursor: "move", background: "#000" },
            textPos: { x: 0, y: -10 },
            props: {
            	// 自己添加 线的属性
            	 id: {
                     name: "id", label: 'Id', value: "", editor: function () {
                    	 return new a.editors.readEditor();
                     }
                 },
                text: {
                    name: "text", label: '名称', value: "", editor: function () {
                        return new a.editors.textEditor()
                    }
                }               
            }
        }, tools: {
            attr: { },
            pointer: {},
            path: {},
            states: { onclick: function (c) { console.log(arguments) }},
            save: {
                onclick: function (c) {
                    console.log('default:\n'+c)
                }
            }
        }, props: { attr: { }, props:[] }, restore: "", activeRects: { rects: [], rectAttr: { stroke: "#ff0000", "stroke-width": 2 } }, historyRects: { rects: [], pathAttr: { path: { stroke: "#00ff00" }, arrow: { stroke: "#00ff00", fill: "#00ff00" } } }
    };
    a.util = {
        isLine: function (g, f, e) {
            var d, c;
            if ((g.x - e.x) == 0) {
                d = 1
            } else {
                d = (g.y - e.y) / (g.x - e.x)
            }
            c = (f.x - e.x) * d + e.y;
            if ((f.y - c) < 10 && (f.y - c) > -10) {
                f.y = c;
                return true
            }
            return false
        }, center: function (d, c) {
            return { x: (d.x - c.x) / 2 + c.x, y: (d.y - c.y) / 2 + c.y }
        }, nextId: (function () {
            var c = 0;
            return function () {
                return ++c
            }
        })(), connPoint: function (j, d) {
            var c = d, e = { x: j.x + j.width / 2, y: j.y + j.height / 2 };
            var l = (e.y - c.y) / (e.x - c.x);
            l = isNaN(l) ? 0 : l;
            var k = j.height / j.width;
            var h = c.y < e.y ? -1 : 1, f = c.x < e.x ? -1 : 1, g, i;
            if (Math.abs(l) > k && h == -1) {
                g = e.y - j.height / 2;
                i = e.x + h * j.height / 2 / l
            } else {
                if (Math.abs(l) > k && h == 1) {
                    g = e.y + j.height / 2;
                    i = e.x + h * j.height / 2 / l
                } else {
                    if (Math.abs(l) < k && f == -1) {
                        g = e.y + f * j.width / 2 * l;
                        i = e.x - j.width / 2
                    } else {
                        if (Math.abs(l) < k && f == 1) {
                            g = e.y + j.width / 2 * l;
                            i = e.x + j.width / 2
                        }
                    }
                }
            }
            return { x: i, y: g }
        }, arrow: function (l, k, d) {
            var g = Math.atan2(l.y - k.y, k.x - l.x) * (180 / Math.PI);
            var h = k.x - d * Math.cos(g * (Math.PI / 180));
            var f = k.y + d * Math.sin(g * (Math.PI / 180));
            var e = h + d * Math.cos((g + 120) * (Math.PI / 180));
            var j = f - d * Math.sin((g + 120) * (Math.PI / 180));
            var c = h + d * Math.cos((g + 240) * (Math.PI / 180));
            var i = f - d * Math.sin((g + 240) * (Math.PI / 180));
            return [k, { x: e, y: j }, { x: c, y: i }]
        }
    };
    a.rect = function (p, m,id) {//添加一个id参数，在构造节点时，如果有id则传入，如果没有则不用传入，系统自动分配一个
        var u = this, g, E = b.extend(true, {}, a.config.rect, p), C = m, t, e, n, f, x, v;
        
        if(id)
			g = id;
		else
            g = "rect" + a.util.nextId();
        var rect_my=C.rect(E.attr.x, E.attr.y, E.attr.width, E.attr.height, E.attr.r);
        t = rect_my.hide().attr(E.attr);        
        e = C.image(a.config.basePath + E.img.src, E.attr.x + E.img.width / 2, E.attr.y + (E.attr.height - E.img.height) / 2, E.img.width, E.img.height).hide();
        n = C.text(E.attr.x + E.img.width + (E.attr.width - E.img.width) / 2, E.attr.y + a.config.lineHeight / 2, E.name.text).hide().attr(E.name);
        f = C.text(E.attr.x + E.img.width + (E.attr.width - E.img.width) / 2, E.attr.y + (E.attr.height - a.config.lineHeight) / 2 + a.config.lineHeight, E.text.text).hide().attr(E.text);
        if(E.showType=='text45')
			rect_my.rotate(45);	
        t.drag(function (r, o) {
            A(r, o)
        }, function () {
            z()
        }, function () {
            l()
        });
        e.drag(function (r, o) {
            A(r, o)
        }, function () {
            z()
        }, function () {
            l()
        });
        n.drag(function (r, o) {
            A(r, o)
        }, function () {
            z()
        }, function () {
            l()
        });
        f.drag(function (r, o) {
            A(r, o)
        }, function () {
            z()
        }, function () {
            l()
        });
        var A = function (F, r) {
            if (!a.config.editable) {
                return
            }
            var o = (x + F);
            var G = (v + r);
            q.x = o - E.margin;
            q.y = G - E.margin;
            B()
        };
        var z = function () {
            x = t.attr("x");
            v = t.attr("y");
            t.attr({ opacity: 0.5 });
            e.attr({ opacity: 0.5 });
            f.attr({ opacity: 0.5 })
        };
        var l = function () {
            t.attr({ opacity: 1 });
            e.attr({ opacity: 1 });
            f.attr({ opacity: 1 })
        };
        var s, i = {}, h = 5, q = { x: E.attr.x - E.margin, y: E.attr.y - E.margin, width: E.attr.width + E.margin * 2, height: E.attr.height + E.margin * 2 };
        s = C.path("M0 0L1 1").hide();
        i.t = C.rect(0, 0, h, h).attr({ fill: "#000", stroke: "#fff", cursor: "s-resize" }).hide().drag(function (r, o) {
            D(r, o, "t")
        }, function () {
            k(this.attr("x") + h / 2, this.attr("y") + h / 2, "t")
        }, function () {
        });
        i.lt = C.rect(0, 0, h, h).attr({ fill: "#000", stroke: "#fff", cursor: "nw-resize" }).hide().drag(function (r, o) {
            D(r, o, "lt")
        }, function () {
            k(this.attr("x") + h / 2, this.attr("y") + h / 2, "lt")
        }, function () {
        });
        i.l = C.rect(0, 0, h, h).attr({ fill: "#000", stroke: "#fff", cursor: "w-resize" }).hide().drag(function (r, o) {
            D(r, o, "l")
        }, function () {
            k(this.attr("x") + h / 2, this.attr("y") + h / 2, "l")
        }, function () {
        });
        i.lb = C.rect(0, 0, h, h).attr({ fill: "#000", stroke: "#fff", cursor: "sw-resize" }).hide().drag(function (r, o) {
            D(r, o, "lb")
        }, function () {
            k(this.attr("x") + h / 2, this.attr("y") + h / 2, "lb")
        }, function () {
        });
        i.b = C.rect(0, 0, h, h).attr({ fill: "#000", stroke: "#fff", cursor: "s-resize" }).hide().drag(function (r, o) {
            D(r, o, "b")
        }, function () {
            k(this.attr("x") + h / 2, this.attr("y") + h / 2, "b")
        }, function () {
        });
        i.rb = C.rect(0, 0, h, h).attr({ fill: "#000", stroke: "#fff", cursor: "se-resize" }).hide().drag(function (r, o) {
            D(r, o, "rb")
        }, function () {
            k(this.attr("x") + h / 2, this.attr("y") + h / 2, "rb")
        }, function () {
        });
        i.r = C.rect(0, 0, h, h).attr({ fill: "#000", stroke: "#fff", cursor: "w-resize" }).hide().drag(function (r, o) {
            D(r, o, "r")
        }, function () {
            k(this.attr("x") + h / 2, this.attr("y") + h / 2, "r")
        }, function () {
        });
        i.rt = C.rect(0, 0, h, h).attr({ fill: "#000", stroke: "#fff", cursor: "ne-resize" }).hide().drag(function (r, o) {
            D(r, o, "rt")
        }, function () {
            k(this.attr("x") + h / 2, this.attr("y") + h / 2, "rt")
        }, function () {
        });
        var D = function (F, r, G) {
            if (!a.config.editable) {
                return
            }
            var o = _bx + F, H = _by + r;
            switch (G) {
                case "t":
                    q.height += q.y - H;
                    q.y = H;
                    break;
                case "lt":
                    q.width += q.x - o;
                    q.height += q.y - H;
                    q.x = o;
                    q.y = H;
                    break;
                case "l":
                    q.width += q.x - o;
                    q.x = o;
                    break;
                case "lb":
                    q.height = H - q.y;
                    q.width += q.x - o;
                    q.x = o;
                    break;
                case "b":
                    q.height = H - q.y;
                    break;
                case "rb":
                    q.height = H - q.y;
                    q.width = o - q.x;
                    break;
                case "r":
                    q.width = o - q.x;
                    break;
                case "rt":
                    q.width = o - q.x;
                    q.height += q.y - H;
                    q.y = H;
                    break
            }
            B()
        };
        var k = function (r, o, F) {
            _bx = r;
            _by = o
        };
        b([t.node, f.node, n.node, e.node]).bind("click", function () {
            if (!a.config.editable) {
                return
            }
            w();
            var o = b(C).data("mod");
            switch (o) {
                case "pointer":
                    break;
                case "path":
                    var r = b(C).data("currNode");
                    if (r && r.getId() != g && r.getId().substring(0, 4) == "rect") {
                        b(C).trigger("addpath", [r, u])
                    }
                    break
            }
            b(C).trigger("click", u);
            b(C).data("currNode", u);
            return false
        });
        var j = function (o, r) {
            if (!a.config.editable) {
                return
            }
            if (r.getId() == g) {
                b(C).trigger("showprops", [E.props, r])
            } else {
                d()
            }
        };
        b(C).bind("click", j);
        var c = function (o, F, r) {
            if (r.getId() == g) {
                f.attr({ text: F })
            }
        };
        b(C).bind("textchange", c);
        function y() {
            return "M" + q.x + " " + q.y + "L" + q.x + " " + (q.y + q.height) + "L" + (q.x + q.width) + " " + (q.y + q.height) + "L" + (q.x + q.width) + " " + q.y + "L" + q.x + " " + q.y
        }
        function w() {
            s.show();
            for (var o in i) {
                i[o].show()
            }
        }
        function d() {
            s.hide();
            for (var o in i) {
                i[o].hide()
            }
        }
        function B() {
            var F = q.x + E.margin, r = q.y + E.margin, G = q.width - E.margin * 2, o = q.height - E.margin * 2;
            t.attr({ x: F, y: r, width: G, height: o });
            switch (E.showType) {
                case "image":
                    e.attr({ x: F + (G - E.img.width) / 2, y: r + (o - E.img.height) / 2 }).show();
                    break;
                case "text":
                    t.show();
                    f.attr({ x: F + G / 2, y: r + o / 2 }).show();
                    break;
                case "text45":
                    t.show();
                    f.attr({ x: F + G / 2, y: r + o / 2 }).show();					
                    break;
                case "image&text":
                    t.show();
                    n.attr({ x: F + E.img.width + (G - E.img.width) / 2, y: r + a.config.lineHeight / 2 }).show();
                    f.attr({ x: F + E.img.width + (G - E.img.width) / 2, y: r + (o - a.config.lineHeight) / 2 + a.config.lineHeight }).show();
                    e.attr({ x: F + E.img.width / 2, y: r + (o - E.img.height) / 2 }).show();
                    break
            }
            i.t.attr({ x: q.x + q.width / 2 - h / 2, y: q.y - h / 2 });
            i.lt.attr({ x: q.x - h / 2, y: q.y - h / 2 });
            i.l.attr({ x: q.x - h / 2, y: q.y - h / 2 + q.height / 2 });
            i.lb.attr({ x: q.x - h / 2, y: q.y - h / 2 + q.height });
            i.b.attr({ x: q.x - h / 2 + q.width / 2, y: q.y - h / 2 + q.height });
            i.rb.attr({ x: q.x - h / 2 + q.width, y: q.y - h / 2 + q.height });
            i.r.attr({ x: q.x - h / 2 + q.width, y: q.y - h / 2 + q.height / 2 });
            i.rt.attr({ x: q.x - h / 2 + q.width, y: q.y - h / 2 });
            s.attr({ path: y() });
            b(C).trigger("rectresize", u)
        }
        this.toJson = function () {
            var r = "{type:'" + E.type + "',text:{text:'" + f.attr("text") + "'}, attr:{ x:" + Math.round(t.attr("x")) + ", y:" + Math.round(t.attr("y")) + ", width:" + Math.round(t.attr("width")) + ", height:" + Math.round(t.attr("height")) + "}, props:{";
            for (var o in E.props) {
                r += o + ":{value:'" + E.props[o].value + "'},"
            }
            if (r.substring(r.length - 1, r.length) == ",") {
                r = r.substring(0, r.length - 1)
            }
            r += "}}";
            return r
        };
        this.restore = function (o) {
            var r = o;
            E = b.extend(true, E, o);
            f.attr({ text: r.text.text });
            B()
        };
        this.getBBox = function () {
            return q
        };
        this.getId = function () {
            return g
        };
        this.remove = function () {
            t.remove();
            f.remove();
            n.remove();
            e.remove();
            s.remove();
            for (var o in i) {
                i[o].remove()
            }
        };
        this.text = function () {
            return f.attr("text")
        };
        this.attr = function (o) {
            if (o) {
                t.attr(o)
            }
        };
        B()
    };
    a.path = function (q, n, u, e,id) {//添加一个id参数，在构造节点时，如果有id则传入，如果没有则不用传入，系统自动分配一个
        var v = this, z = n, B = b.extend(true, {}, a.config.path), i, t, f, h = B.textPos, y, w, k = u, s = e, g, x;
        if(id)
			g = id;
		else
			g = "path" + a.util.nextId();        
        function p(G, H, D, L) {
            var F = this, M = G, r, o = D, O = L, K, I, N = H;
            switch (M) {
                case "from":
                    r = z.rect(H.x - B.attr.fromDot.width / 2, H.y - B.attr.fromDot.height / 2, B.attr.fromDot.width, B.attr.fromDot.height).attr(B.attr.fromDot);
                    break;
                case "big":
                    r = z.rect(H.x - B.attr.bigDot.width / 2, H.y - B.attr.bigDot.height / 2, B.attr.bigDot.width, B.attr.bigDot.height).attr(B.attr.bigDot);
                    break;
                case "small":
                    r = z.rect(H.x - B.attr.smallDot.width / 2, H.y - B.attr.smallDot.height / 2, B.attr.smallDot.width, B.attr.smallDot.height).attr(B.attr.smallDot);
                    break;
                case "to":
                    r = z.rect(H.x - B.attr.toDot.width / 2, H.y - B.attr.toDot.height / 2, B.attr.toDot.width, B.attr.toDot.height).attr(B.attr.toDot);
                    break
            }
            if (r && (M == "big" || M == "small")) {
                r.drag(function (Q, P) {
                    C(Q, P)
                }, function () {
                    J()
                }, function () {
                    E()
                });
                var C = function (R, Q) {
                    var P = (K + R), S = (I + Q);
                    F.moveTo(P, S)
                };
                var J = function () {
                    if (M == "big") {
                        K = r.attr("x") + B.attr.bigDot.width / 2;
                        I = r.attr("y") + B.attr.bigDot.height / 2
                    }
                    if (M == "small") {
                        K = r.attr("x") + B.attr.smallDot.width / 2;
                        I = r.attr("y") + B.attr.smallDot.height / 2
                    }
                };
                var E = function () {
                }
            }
            this.type = function (P) {
                if (P) {
                    M = P
                } else {
                    return M
                }
            };
            this.node = function (P) {
                if (P) {
                    r = P
                } else {
                    return r
                }
            };
            this.left = function (P) {
                if (P) {
                    o = P
                } else {
                    return o
                }
            };
            this.right = function (P) {
                if (P) {
                    O = P
                } else {
                    return O
                }
            };
            this.remove = function () {
                o = null;
                O = null;
                r.remove()
            };
            this.pos = function (P) {
                if (P) {
                    N = P;
                    r.attr({ x: N.x - r.attr("width") / 2, y: N.y - r.attr("height") / 2 });
                    return this
                } else {
                    return N
                }
            };
            this.moveTo = function (Q, T) {
                this.pos({ x: Q, y: T });
                switch (M) {
                    case "from":
                        if (O && O.right() && O.right().type() == "to") {
                            O.right().pos(a.util.connPoint(s.getBBox(), N))
                        }
                        if (O && O.right()) {
                            O.pos(a.util.center(N, O.right().pos()))
                        }
                        break;
                    case "big":
                        if (O && O.right() && O.right().type() == "to") {
                            O.right().pos(a.util.connPoint(s.getBBox(), N))
                        }
                        if (o && o.left() && o.left().type() == "from") {
                            o.left().pos(a.util.connPoint(k.getBBox(), N))
                        }
                        if (O && O.right()) {
                            O.pos(a.util.center(N, O.right().pos()))
                        }
                        if (o && o.left()) {
                            o.pos(a.util.center(N, o.left().pos()))
                        }
                        var S = { x: N.x, y: N.y };
                        if (a.util.isLine(o.left().pos(), S, O.right().pos())) {
                            M = "small";
                            r.attr(B.attr.smallDot);
                            this.pos(S);
                            var P = o;
                            o.left().right(o.right());
                            o = o.left();
                            P.remove();
                            var R = O;
                            O.right().left(O.left());
                            O = O.right();
                            R.remove()
                        }
                        break;
                    case "small":
                        if (o && O && !a.util.isLine(o.pos(), { x: N.x, y: N.y }, O.pos())) {
                            M = "big";
                            r.attr(B.attr.bigDot);
                            var P = new p("small", a.util.center(o.pos(), N), o, o.right());
                            o.right(P);
                            o = P;
                            var R = new p("small", a.util.center(O.pos(), N), O.left(), O);
                            O.left(R);
                            O = R
                        }
                        break;
                    case "to":
                        if (o && o.left() && o.left().type() == "from") {
                            o.left().pos(a.util.connPoint(k.getBBox(), N))
                        }
                        if (o && o.left()) {
                            o.pos(a.util.center(N, o.left().pos()))
                        }
                        break
                }
                m()
            }
        }
        function j() {
            var D, C, E = k.getBBox(), F = s.getBBox(), r, o;
            r = a.util.connPoint(E, { x: F.x + F.width / 2, y: F.y + F.height / 2 });
            o = a.util.connPoint(F, r);
            D = new p("from", r, null, new p("small", { x: (r.x + o.x) / 2, y: (r.y + o.y) / 2 }));
            D.right().left(D);
            C = new p("to", o, D.right(), null);
            D.right().right(C);
            this.toPathString = function () {
                if (!D) {
                    return ""
                }
                var J = D, I = "M" + J.pos().x + " " + J.pos().y, H = "";
                while (J.right()) {
                    J = J.right();
                    I += "L" + J.pos().x + " " + J.pos().y
                }
                var G = a.util.arrow(J.left().pos(), J.pos(), B.attr.arrow.radius);
                H = "M" + G[0].x + " " + G[0].y + "L" + G[1].x + " " + G[1].y + "L" + G[2].x + " " + G[2].y + "z";
                return [I, H]
            };
            this.toJson = function () {
                var G = "[", H = D;
                while (H) {
                    if (H.type() == "big") {
                        G += "{x:" + Math.round(H.pos().x) + ",y:" + Math.round(H.pos().y) + "},"
                    }
                    H = H.right()
                }
                if (G.substring(G.length - 1, G.length) == ",") {
                    G = G.substring(0, G.length - 1)
                }
                G += "]";
                return G
            };
            this.restore = function (H) {
                var I = H, J = D.right();
                for (var G = 0; G < I.length; G++) {
                    J.moveTo(I[G].x, I[G].y);
                    J.moveTo(I[G].x, I[G].y);
                    J = J.right()
                }
                this.hide()
            };
            this.fromDot = function () {
                return D
            };
            this.toDot = function () {
                return C
            };
            this.midDot = function () {
                var H = D.right(), G = D.right().right();
                while (G.right() && G.right().right()) {
                    G = G.right().right();
                    H = H.right()
                }
                return H
            };
            this.show = function () {
                var G = D;
                while (G) {
                    G.node().show();
                    G = G.right()
                }
            };
            this.hide = function () {
                var G = D;
                while (G) {
                    G.node().hide();
                    G = G.right()
                }
            };
            this.remove = function () {
                var G = D;
                while (G) {
                    if (G.right()) {
                        G = G.right();
                        G.left().remove()
                    } else {
                        G.remove();
                        G = null
                    }
                }
            }
        }
        B = b.extend(true, B, q);
        i = z.path(B.attr.path.path).attr(B.attr.path);
        t = z.path(B.attr.arrow.path).attr(B.attr.arrow);
        x = new j();
        x.hide();
        f = z.text(0, 0, B.text.text).attr(B.text).attr({ text: B.text.text.replace("{from}", k.text()).replace("{to}", s.text()) });
        f.drag(function (r, o) {
            if (!a.config.editable) {
                return
            }
            f.attr({ x: y + r, y: w + o })
        }, function () {
            y = f.attr("x");
            w = f.attr("y")
        }, function () {
            var o = x.midDot().pos();
            h = { x: f.attr("x") - o.x, y: f.attr("y") - o.y }
        });
        m();
        b([i.node, t.node]).bind("click", function () {
            if (!a.config.editable) {
                return
            }
            b(z).trigger("click", v);
            b(z).data("currNode", v);
            return false
        });
        var l = function (r, C) {
            if (!a.config.editable) {
                return
            }
            if (C && C.getId() == g) {
                x.show();
                b(z).trigger("showprops", [B.props, v])
            } else {
                x.hide()
            }
            var o = b(z).data("mod");
            switch (o) {
                case "pointer":
                    break;
                case "path":
                    break
            }
        };
        b(z).bind("click", l);
        var A = function (o, r) {
            if (!a.config.editable) {
                return
            }
            if (r && (r.getId() == k.getId() || r.getId() == s.getId())) {
                b(z).trigger("removepath", v)
            }
        };
        b(z).bind("removerect", A);
        var d = function (C, D) {
            if (!a.config.editable) {
                return
            }
            if (k && k.getId() == D.getId()) {
                var o;
                if (x.fromDot().right().right().type() == "to") {
                    o = { x: s.getBBox().x + s.getBBox().width / 2, y: s.getBBox().y + s.getBBox().height / 2 }
                } else {
                    o = x.fromDot().right().right().pos()
                }
                var r = a.util.connPoint(k.getBBox(), o);
                x.fromDot().moveTo(r.x, r.y);
                m()
            }
            if (s && s.getId() == D.getId()) {
                var o;
                if (x.toDot().left().left().type() == "from") {
                    o = { x: k.getBBox().x + k.getBBox().width / 2, y: k.getBBox().y + k.getBBox().height / 2 }
                } else {
                    o = x.toDot().left().left().pos()
                }
                var r = a.util.connPoint(s.getBBox(), o);
                x.toDot().moveTo(r.x, r.y);
                m()
            }
        };
        b(z).bind("rectresize", d);
        var c = function (r, o, C) {
            if (C.getId() == g) {
                f.attr({ text: o })
            }
        };
        b(z).bind("textchange", c);
        this.from = function () {
            return k
        };
        this.to = function () {
            return s
        };
        this.toJson = function () {
            var r = "{from:'" + k.getId() + "',to:'" + s.getId() + "', dots:" + x.toJson() + ",text:{text:'" + f.attr("text") + "'},textPos:{x:" + Math.round(h.x) + ",y:" + Math.round(h.y) + "}, props:{";
            for (var o in B.props) {
                r += o + ":{value:'" + B.props[o].value + "'},"
            }
            if (r.substring(r.length - 1, r.length) == ",") {
                r = r.substring(0, r.length - 1)
            }
            r += "}}";
            return r
        };
        this.restore = function (o) {
            var r = o;
            B = b.extend(true, B, o);
            x.restore(r.dots)
        };
        this.remove = function () {
            x.remove();
            i.remove();
            t.remove();
            f.remove();
            try {
                b(z).unbind("click", l)
            } catch (o) {
            }
            try {
                b(z).unbind("removerect", A)
            } catch (o) {
            }
            try {
                b(z).unbind("rectresize", d)
            } catch (o) {
            }
            try {
                b(z).unbind("textchange", c)
            } catch (o) {
            }
        };
        function m() {
            var r = x.toPathString(), o = x.midDot().pos();
            i.attr({ path: r[0] });
            t.attr({ path: r[1] });
            f.attr({ x: o.x + h.x, y: o.y + h.y })
        }
        this.getId = function () {
            return g
        };
        this.text = function () {
            return f.attr("text")
        };
        this.attr = function (o) {
            if (o && o.path) {
                i.attr(o.path)
            }
            if (o && o.arrow) {
                t.attr(o.arrow)
            }
        }
    };
    a.props = function (h, f) {
        // zhanglongfei modify 
        b("#myflow_props").hide().draggable({ handle: "#myflow_props_handle" }).resizable().css(a.config.props.attr).bind("click", function () {
            return false
        });
        if(typeof a.config.showPropsExtend !== "undefined"){
            b(f).bind("showprops", a.config.showPropsExtend)
        }

        // var j = this, c = b("#myflow_props").hide().draggable({ handle: "#myflow_props_handle" }).resizable().css(a.config.props.attr).bind("click", function () {
        //     return false
        // }), e = c.find("table"), g = f, i;

        // var d = function (n, m, o) {
        //     if (i && i.getId() == o.getId()) {
        //         return
        //     }
            
        //     i = o;
        //     b(e).find(".editor").each(function () {
        //         var k = b(this).data("editor");
        //         if (k) {
        //             k.destroy()
        //         }
        //     });
        //     e.empty();
        //     c.show();                      
        //     for (var l in m) {            	
        //         e.append("<tr><th>" + m[l].label + '</th><td><div id="p' + l + '" class="editor"></div></td></tr>');
        //         if (m[l].editor) {
        //             m[l].editor().init(m, l, "p" + l, o, g)
        //         }
        //     }
        //     // showPropsExtend(e,m,c);
        // };
        // b(g).bind("showprops", d)
    };
    a.editors = {
        textEditor: function () {
            var d, e, c, g, f;
            this.init = function (i, h, m, l, j) {
                d = i;
                e = h;
                c = m;
                g = l;
                f = j;                
                b('<input  style="width:100%;"/>').val(g.text()).change(function () {
                    i[e].value = b(this).val();
                    b(f).trigger("textchange", [b(this).val(), g])
                }).appendTo("#" + c);
                b("#" + c).data("editor", this)
            };
            this.destroy = function () {
                b("#" + c + " input").each(function () {
                    d[e].value = b(this).val();
                    b(f).trigger("textchange", [b(this).val(), g])
                })
            }
        },
        //添加一个自定义的只读编辑框
        readEditor : function(){
    		var _props,_k,_div,_src,_r;
    		this.init = function(props, k, div, src, r){
    			_props=props; _k=k; _div=div; _src=src; _r=r;    			
    			$('<input style="width:100%;" readonly />').val(props[_k].value).change(function(){
    				props[_k].value = $(this).val();
    			}).appendTo('#'+_div);
    			
    			$('#'+_div).data('editor', this);
    		}
    		this.destroy = function(){
    			$('#'+_div+' input').each(function(){
    				_props[_k].value = $(this).val();
    			});
    		}
    	}
    };
    a.init = function (x, r) {
        var v = b(window).width(), e = b(window).height(), y = Raphael(x, v * 1.5, e * 1.5), q = {}, g = {};
        b.extend(true, a.config, r);
        b(document).keydown(function (i,byButton) {
            if (!a.config.editable) {
                return
            }
            if (i.keyCode == 46||byButton) {//
                var j = b(y).data("currNode");
                if (j) {
                    if (j.getId().substring(0, 4) == "rect") {
                        b(y).trigger("removerect", j)
                    } else {
                        if (j.getId().substring(0, 4) == "path") {
                            b(y).trigger("removepath", j)
                        }
                    }
                    b(y).removeData("currNode")
                }
            }
        });
        b(document).click(function () {
            b(y).data("currNode", null);
            b(y).trigger("click", {
                getId: function () {
                    return "00000000"
                }
            });
            b(y).trigger("showprops", [a.config.props.props, {
                getId: function () {
                    return "00000000"
                }
            }])
        });
        var w = function (c, i) {
            if (!a.config.editable) {
                return
            }
            if (i.getId().substring(0, 4) == "rect") {
                q[i.getId()] = null;
                i.remove()
            } else {
                if (i.getId().substring(0, 4) == "path") {
                    g[i.getId()] = null;
                    i.remove()
                }
            }
        };
        b(y).bind("removepath", w);
        b(y).bind("removerect", w);
        b(y).bind("addrect", function (j, c, k) {
            var i = new a.rect(b.extend(true, {}, a.config.tools.states[c], k), y);
            q[i.getId()] = i
        });
        var f = function (i, k, j) {
            var c = new a.path({}, y, k, j);
            g[c.getId()] = c
        };
        b(y).bind("addpath", f);
        b(y).data("mod", "point");
        if (a.config.editable) {
            b("#myflow_tools").draggable({ handle: "#myflow_tools_handle" }).css(a.config.tools.attr);
            b("#myflow_tools .node").hover(function () {
                b(this).addClass("mover")
            }, function () {
                b(this).removeClass("mover")
            });
            b("#myflow_tools .selectable").click(function () {
                b(".selected").removeClass("selected");
                b(this).addClass("selected");
                b(y).data("mod", this.id)
            });
            b("#myflow_tools .state").each(function () {
                b(this).draggable({ helper: "clone" })
            });
            b(x).droppable({
                accept: ".state", drop: function (c, i) {
                    // add by zhanglongfei,由于新系统是单页面应用，所以需要去掉上方和左侧的位置
                    var $selfOffset = b(this).offset()
                    var xPosition = i.helper.offset().left - $selfOffset.left
                    var yPosition = i.helper.offset().top - $selfOffset.top
                    b(y).trigger("addrect", [i.helper.attr("type"), { attr: { x: xPosition, y: yPosition } }])
                    // b(y).trigger("addrect", [i.helper.attr("type"), { attr: { x: i.helper.offset().left, y: i.helper.offset().top } }])
                }
            });
            b("#myflow_save").click(function () {
                var i = "{states:{";
                for (var c in q) {
                    if (q[c]) {
                        i += q[c].getId() + ":" + q[c].toJson() + ","
                    }
                }
                if (i.substring(i.length - 1, i.length) == ",") {
                    i = i.substring(0, i.length - 1)
                }
                i += "},paths:{";
                for (var c in g) {
                    if (g[c]) {
                        i += g[c].getId() + ":" + g[c].toJson() + ","
                    }
                }
                if (i.substring(i.length - 1, i.length) == ",") {
                    i = i.substring(0, i.length - 1)
                }
                i += "},props:{props:{";
                for (var c in a.config.props.props) {
                    i += c + ":{value:'" + a.config.props.props[c].value + "'},"
                }
                if (i.substring(i.length - 1, i.length) == ",") {
                    i = i.substring(0, i.length - 1)
                }
                i += "}}}";
                a.config.tools.save.onclick(i)
            });
            new a.props({}, y)
        }
        if (r.restore) {
            var B = r.restore;
            var z = {};
            if (B.states) {
                for (var s in B.states) {
                    var d = new a.rect(b.extend(true, {}, a.config.tools.states[B.states[s].type], B.states[s]), y,s);
                    d.restore(B.states[s]);
                    z[s] = d;
                    q[d.getId()] = d
                }
            }
            if (B.paths) {
                for (var s in B.paths) {
                    var n = new a.path(b.extend(true, {}, a.config.tools.path, B.paths[s]), y, z[B.paths[s].from], z[B.paths[s].to],s);
                    n.restore(B.paths[s]);                    
                    g[n.getId()] = n
                }
            }
        }
        //设置历史、当前的节点和线
        var historyRects = a.config.historyRects, activeRects = a.config.activeRects;
        if (historyRects.rects.length || activeRects.rects.length) {
            var m = {}, z = {};
            for (var h in g) {
                if (!z[g[h].from().getId()]) {
                    z[g[h].from().getId()] = { rect: g[h].from(), paths: {} }
                }
                z[g[h].from().getId()].paths[g[h].getId()] = g[h];
                if (!z[g[h].to().getId()]) {
                    z[g[h].to().getId()] = { rect: g[h].to(), paths: {} }
                }
            }
            for (var u = 0; u < historyRects.rects.length; u++) {
                if (z[historyRects.rects[u].code]) {
                    z[historyRects.rects[u].code].rect.attr(historyRects.rectAttr)
                }
                for (var t = 0; t < historyRects.rects[u].paths.length; t++) {
                    if (z[historyRects.rects[u].code].paths[historyRects.rects[u].paths[t]]) {
                        z[historyRects.rects[u].code].paths[historyRects.rects[u].paths[t]].attr(historyRects.pathAttr)
                    }
                }
            }
            for (var u = 0; u < activeRects.rects.length; u++) {
                if (z[activeRects.rects[u].code]) {
                    z[activeRects.rects[u].code].rect.attr(activeRects.rectAttr)
                }
                for (var t = 0; t < activeRects.rects[u].paths.length; t++) {
                    if (z[activeRects.rects[u].code].paths[activeRects.rects[u].paths[t]]) {
                        z[activeRects.rects[u].code].paths[activeRects.rects[u].paths[t]].attr(activeRects.pathAttr)
                    }
                }
            }
        }
    };
    b.fn.myflow = function (c) {
        return this.each(function () {
            a.init(this, c)
        })
    };
    b.myflow = a
})(jQuery);
